'use strict'
import {
  Model,
  DataTypes,
  InferAttributes,
  InferCreationAttributes,
  CreationOptional,
} from 'sequelize'
import { BadRequest } from 'http-errors'
import bcrypt from 'bcryptjs'
import dayjs from 'dayjs'
import { Models } from '../type'
import sequelize from '.'

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
  declare id: CreationOptional<number>
  declare email: string
  declare username: string
  declare password: string
  declare nickname: string
  declare avatar: CreationOptional<string>
  declare gender: number
  declare roleId: number
  declare expiredAt: CreationOptional<Date>
  declare createdAt: CreationOptional<Date>
  declare updatedAt: CreationOptional<Date>

  static associate(models: Models) {
    User.hasMany(models.Attachment, { as: 'attachments' })
    User.hasMany(models.Order, { as: 'orders' })
    User.belongsTo(models.Role, { as: 'role', foreignKey: 'roleId' })
  }
}

User.init(
  {
    id: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      primaryKey: true,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: {
        name: 'email',
        msg: '邮箱已存在，请直接登录。',
      },
      validate: {
        notNull: {
          msg: '邮箱必须填写。',
        },
        notEmpty: {
          msg: '邮箱不能为空。',
        },
        isEmail: {
          msg: '邮箱格式不正确。',
        },
      },
    },
    username: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: {
        name: 'username',
        msg: '用户名已经存在。',
      },
      validate: {
        notNull: {
          msg: '用户名必须填写。',
        },
        notEmpty: {
          msg: '用户名不能为空。',
        },
        len: {
          args: [2, 45],
          msg: '用户名长度必须在2~45个字符之间。',
        },
      },
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notNull: {
          msg: '密码必须填写。',
        },
        notEmpty: {
          msg: '密码不能为空。',
        },
      },
      // set里的new Error不输入sequelize验证
      set(value: string) {
        if (!value) {
          throw new BadRequest('密码必须填写。')
        }
        if (value.length < 6 || value.length > 45) {
          throw new BadRequest('密码长度必须在6~45个字符之间。')
        }
        this.setDataValue('password', bcrypt.hashSync(value))
      },
    },
    nickname: {
      type: DataTypes.STRING,
      allowNull: false,
      validate: {
        notNull: {
          msg: '昵称必须填写。',
        },
        notEmpty: {
          msg: '昵称不能为空。',
        },
        len: {
          args: [2, 45],
          msg: '昵称长度必须在2~45个字符之间。',
        },
      },
    },
    avatar: {
      type: DataTypes.STRING,
      validate: {
        isUrl: {
          msg: '图片地址不正确。',
        },
      },
    },
    gender: {
      type: DataTypes.TINYINT,
      allowNull: false,
      defaultValue: 2,
      validate: {
        notNull: {
          msg: '性别必须填写。',
        },
        notEmpty: {
          msg: '性别不能为空。',
        },
        isIn: {
          args: [[0, 1, 2]],
          msg: '性别的值必须是 0:男性, 1:女性, 2:未选择。',
        },
      },
    },
    roleId: DataTypes.INTEGER,
    expiredAt: {
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      get() {
        return this.getDataValue('expiredAt')
          ? dayjs(this.getDataValue('expiredAt')).format('YYYY-MM-DD HH:mm:ss')
          : null
      },
    },
    createdAt: {
      type: DataTypes.DATE,
      get() {
        return this.getDataValue('createdAt')
          ? dayjs(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm:ss')
          : null
      },
    },
    updatedAt: {
      type: DataTypes.DATE,
      get() {
        return this.getDataValue('createdAt')
          ? dayjs(this.getDataValue('createdAt')).format('YYYY-MM-DD HH:mm:ss')
          : null
      },
    },
  },
  {
    sequelize,
    modelName: 'User',
  },
)

export default User
